package com.ouc.common.utils;


import org.springframework.lang.NonNull;

import java.lang.reflect.Array;
import java.util.*;

public class ArrayUtils {

  private ArrayUtils() {
  }

  /**
   * 一维数组数据类型转换 byte[] --> float[]
   *
   * @param arr
   * @return float 类型一维数组
   */
  @NonNull
  public static float[] transformByte1D(@NonNull byte[] arr) {
    float[] arr1D = new float[arr.length];
    for (int i = 0; i < arr.length; i++) {
      arr1D[i] = arr[i];
    }
    return arr1D;
  }

  /**
   * 一维数组数据类型转换 short[] --> float[]
   *
   * @param arr
   * @return float 类型一维数组
   */
  @NonNull
  public static float[] transformShort1D(@NonNull short[] arr) {
    float[] arr1D = new float[arr.length];
    for (int i = 0; i < arr.length; i++) {
      arr1D[i] = arr[i];
    }
    return arr1D;
  }

  /**
   * 一维数组数据类型转换 int[] --> float[]
   *
   * @param arr
   * @return float 类型一维数组
   */
  @NonNull
  public static float[] transformInt1D(@NonNull int[] arr) {
    float[] arr1D = new float[arr.length];
    for (int i = 0; i < arr.length; i++) {
      arr1D[i] = arr[i];
    }
    return arr1D;
  }

  /**
   * 一维数组数据类型转换 long[] --> float[]
   *
   * @param arr
   * @return float 类型一维数组
   */
  @NonNull
  public static float[] transformLong1D(@NonNull long[] arr) {
    float[] arr1D = new float[arr.length];
    for (int i = 0; i < arr.length; i++) {
      arr1D[i] = arr[i];
    }
    return arr1D;
  }

  /**
   * 一维数组数据类型转换 double[] --> float[]
   *
   * @param arr
   * @return float 类型一维数组
   */
  @NonNull
  public static float[] transformDouble1D(@NonNull double[] arr) {
    float[] arr1D = new float[arr.length];
    for (int i = 0; i < arr.length; i++) {
      arr1D[i] = (float) arr[i];
    }
    return arr1D;
  }

  /**
   * 二维数组数据类型转换 byte[][] --> float[][]
   *
   * @param arr
   * @return float 类型二维数组
   */
  @NonNull
  public static float[][] transformByte2D(@NonNull byte[][] arr) {
    float[][] arr2D = new float[arr.length][];
    for (int i = 0; i < arr.length; i++) {
      float[] temp = new float[arr[i].length];
      for (int j = 0; j < temp.length; j++) {
        temp[j] = arr[i][j];
      }
      arr2D[i] = temp;
    }
    return arr2D;
  }

  /**
   * 二维数组数据类型转换 short[][] --> float[][]
   *
   * @param arr
   * @return float 类型二维数组
   */
  @NonNull
  public static float[][] transformShort2D(@NonNull short[][] arr) {
    float[][] arr2D = new float[arr.length][];
    for (int i = 0; i < arr.length; i++) {
      float[] temp = new float[arr[i].length];
      for (int j = 0; j < temp.length; j++) {
        temp[j] = arr[i][j];
      }
      arr2D[i] = temp;
    }
    return arr2D;
  }

  /**
   * 二维数组数据类型转换 int[][] --> float[][]
   *
   * @param arr
   * @return float 类型二维数组
   */
  @NonNull
  public static float[][] transformInt2D(@NonNull int[][] arr) {
    float[][] arr2D = new float[arr.length][];
    for (int i = 0; i < arr.length; i++) {
      float[] temp = new float[arr[i].length];
      for (int j = 0; j < temp.length; j++) {
        temp[j] = arr[i][j];
      }
      arr2D[i] = temp;
    }
    return arr2D;
  }

  /**
   * 二维数组数据类型转换 long[][] --> float[][]
   *
   * @param arr
   * @return float 类型二维数组
   */
  @NonNull
  public static float[][] transformLong2D(@NonNull long[][] arr) {
    float[][] arr2D = new float[arr.length][];
    for (int i = 0; i < arr.length; i++) {
      float[] temp = new float[arr[i].length];
      for (int j = 0; j < temp.length; j++) {
        temp[j] = arr[i][j];
      }
      arr2D[i] = temp;
    }
    return arr2D;
  }

  /**
   * 二维数组数据类型转换 double[][] --> float[][]
   *
   * @param arr
   * @return float 类型二维数组
   */
  @NonNull
  public static float[][] transformDouble2D(@NonNull double[][] arr) {
    float[][] arr2D = new float[arr.length][];
    for (int i = 0; i < arr.length; i++) {
      float[] temp = new float[arr[i].length];
      for (int j = 0; j < temp.length; j++) {
        temp[j] = (float) arr[i][j];
      }
      arr2D[i] = temp;
    }
    return arr2D;
  }

  /**
   * 三维数组数据类型转换 double[][][] --> float[][][]
   *
   * @param arr
   * @return float 类型三维数组
   */
  /**
   * 三维数组数据类型转换 double[][][] --> float[][][]
   *
   * @param arr 数组
   * @return float 类型三维数组
   */
  @NonNull
  public static float[][][] transformDouble3D(@NonNull double[][][] arr) {
    float[][][] arr3D = new float[arr.length][][];
    for (int i = 0; i < arr.length; i++) {
      float[][] temp = new float[arr[i].length][];
      for (int j = 0; j < temp.length; j++) {
        float[] temp1 = new float[arr[i][j].length];
        for (int k = 0; k < arr[i][j].length; k++) {
          temp1[k] = (float) arr[i][j][k];
        }
        temp[j] = temp1;
      }
      arr3D[i] = temp;
    }
    return arr3D;
  }

  /**
   * 三维数组数据类型转换 byte[][][] --> float[][][]
   *
   * @param arr 数组
   * @return float 类型三维数组
   */
  @NonNull
  public static float[][][] transformByte3D(@NonNull byte[][][] arr) {
    float[][][] arr3D = new float[arr.length][][];
    for (int i = 0; i < arr.length; i++) {
      float[][] temp = new float[arr[i].length][];
      for (int j = 0; j < temp.length; j++) {
        float[] temp1 = new float[arr[i][j].length];
        for (int k = 0; k < temp.length; k++) {
          temp1[k] = arr[i][j][k];
        }
        temp[j] = temp1;
      }
      arr3D[i] = temp;
    }
    return arr3D;
  }

  /**
   * 三维数组数据类型转换 short[][][] --> float[][][]
   *
   * @param arr 数组
   * @return float 类型三维数组
   */
  @NonNull
  public static float[][][] transformShort3D(@NonNull short[][][] arr) {
    float[][][] arr3D = new float[arr.length][][];
    for (int i = 0; i < arr.length; i++) {
      float[][] temp = new float[arr[i].length][];
      for (int j = 0; j < temp.length; j++) {
        float[] temp1 = new float[arr[i][j].length];
        for (int k = 0; k < temp1.length; k++) {
          temp1[k] = arr[i][j][k];
        }
        temp[j] = temp1;
      }
      arr3D[i] = temp;
    }
    return arr3D;
  }

  /**
   * 三维数组数据类型转换 int[][][] --> float[][][]
   *
   * @param arr 数组
   * @return float 类型三维数组
   */
  @NonNull
  public static float[][][] transformInt3D(@NonNull int[][][] arr) {
    float[][][] arr3D = new float[arr.length][][];
    for (int i = 0; i < arr3D.length; i++) {
      float[][] temp = new float[arr[i].length][];
      for (int j = 0; j < temp.length; j++) {
        float[] temp1 = new float[arr[i][j].length];
        for (int k = 0; k < temp1.length; k++) {
          temp1[k] = arr[i][j][k];
        }
        temp[j] = temp1;
      }
      arr3D[i] = temp;
    }
    return arr3D;
  }

  /**
   * 三维数组数据类型转换 long[][][] --> float[][][]
   *
   * @param arr 数组
   * @return float 类型三维数组
   */
  @NonNull
  public static float[][][] transformLong3D(@NonNull long[][][] arr) {
    float[][][] arr3D = new float[arr.length][][];
    for (int i = 0; i < arr3D.length; i++) {
      float[][] temp = new float[arr[i].length][];
      for (int j = 0; j < temp.length; j++) {
        float[] temp1 = new float[arr[i][j].length];
        for (int k = 0; k < temp1.length; k++) {
          temp1[k] = arr[i][j][k];
        }
        temp[j] = temp1;
      }
      arr3D[i] = temp;
    }
    return arr3D;
  }

  /**
   * 截取二维数组的方法，从二维数组中截取部分数组，形成新数组
   *
   * @param arr 原数组
   * @param x1  行起始位置
   * @param x2  行终止位置（不包括终止为止）
   * @param y1  列起始位置
   * @param y2  列终止位置（不包括终止为止）
   * @return 截取后的新数组
   */
  @NonNull
  public static float[][] partFloat2D(@NonNull float[][] arr, int x1, int x2, int y1, int y2) {
    float[][] arr2D = new float[x2 - x1][y2 - y1];
    for (int i = 0; i < arr2D.length; i++) {
      arr2D[i] = Arrays.copyOfRange(arr[x1 + i], y1, y2);
    }
    return arr2D;
  }

  /**
   * 截取二维数组的方法，从二维数组中截取部分数组，形成新数组
   *
   * @param arr 原数组
   * @param x1  行起始位置
   * @param x2  行终止位置（不包括终止为止）
   * @param y1  列起始位置
   * @param y2  列终止位置（不包括终止为止）
   * @return 截取后的新数组
   */
  @NonNull
  public static double[][] partDouble2D(@NonNull double[][] arr, int x1, int x2, int y1, int y2) {
    double[][] arr2D = new double[x2 - x1][y2 - y1];
    for (int i = 0; i < arr2D.length; i++) {
      arr2D[i] = Arrays.copyOfRange(arr[x1 + i], y1, y2);
    }
    return arr2D;
  }

  /**
   * 获取传入值在已排序数组中的对应位置
   * 若key值刚好存在，返回对应下标值；若key值在两个数之间，返回较小的下标；
   * 若key值过大，返回数组长度-1；若key值过小，返回 0
   * 不能使用二分查找，因为不能确定数组从大到小还是从小到大排列
   *
   * @param arr 有顺序的一维数组
   * @param key 数组值
   * @return 数组下标
   */
  public static int getArrayIndex(float[] arr, float key) {
    if (arr.length == 1) {
      return 0;
    }
    for (int i = 1; i < arr.length; i++) {
      if (key == MathUtils.middle(key, arr[i - 1], arr[i])) {
        return i;
      }
    }
    if (arr[0] < arr[1]) //数组升序排列
    {
      return key < arr[0] ? 0 : arr.length - 1;
    } else  //数组降序排列
    {
      return key > arr[0] ? 0 : arr.length - 1;
    }
  }

  /**
   * 获取值在数组中的位置
   * 如果存在返回对应的位置（从0开始）
   * 通过与数组中某个值相减如果小于偏差（此方法认为是0）认为是同一个值
   * 如果还没有通过中间值寻找
   * 如果不存在返回所在的中间值位置的后一个
   * 例如{1,3}里面找2，会找到位置是1
   * 如果不存在返回数组的长度-1
   *
   * @param arr 原始数组
   * @param key 要寻找的值
   * @return
   */
  public static int getArrayIndexFormArr(float[] arr, float key) {
    return getArrayIndexFormArr(arr, key, 0);
  }

  /**
   * 获取值在数组中的位置
   * 如果存在返回对应的位置（从0开始）
   * 通过与数组中某个值相减如果小于偏差认为是同一个值
   * 如果还没有通过中间值寻找
   * 如果不存在返回所在的中间值位置的后一个
   * 例如{1,3}里面找2，会找到位置是1
   * 如果不存在返回数组的长度-1
   *
   * @param arr   原始数组
   * @param key   要寻找的值
   * @param scale 偏差
   * @return
   */
  public static int getArrayIndexFormArr(float[] arr, float key, float scale) {
    if (arr.length == 1) {
      return 0;
    }
    for (int i = 0; i < arr.length; i++) {
      if (Math.abs(Arith.sub(key, arr[i])) <= scale) {
        return i;
      }
    }
    for (int i = 1; i < arr.length; i++) {
      if (key == MathUtils.middle(key, arr[i - 1], arr[i])) {
        return i;
      }
    }

    if (arr[0] <= arr[1]) //数组升序排列
    {
      return key < arr[0] ? 0 : arr.length - 1;
    } else  //数组降序排列
    {
      return key > arr[0] ? 0 : arr.length - 1;
    }
  }

  /**
   * 获取传入值在已排序数组中的对应位置
   * 若key值刚好存在，返回对应下标值；若key值在两个数之间，返回较小的下标；
   * 若key值过大，返回数组长度-1；若key值过小，返回 0
   *
   * @param arr 有顺序的一维数组
   * @param key 数组值
   * @return 数组下标
   */
  public static int getArrayIndex(double[] arr, double key) {
    for (int i = 1; i < arr.length; i++) {
      if (key == MathUtils.middle(key, arr[i - 1], arr[i])) {
        return i - 1;
      }
    }
    if (arr[0] < arr[1]) //数组升序排列
    {
      return key < arr[0] ? 0 : arr.length - 1;
    } else  //数组降序排列
    {
      return key > arr[0] ? 0 : arr.length - 1;
    }
  }

  /**
   * 数组扁平化处理。将二维数组转为 1 维数组
   * 为方便实现，二维数组为规则矩阵数组
   *
   * @param obj 二维 int 类型数组
   * @return 一维数组
   */
  public static int[] flat2D(int[][] obj) {
    int row = obj.length;
    int column = obj[0].length;
    int[] ret = new int[row * column];
    for (int i = 0; i < row; i++) {
      for (int j = 0; j < column; j++) {
        ret[i * column + j] = obj[i][j];
      }
    }
    return ret;
  }

  /**
   * 数组扁平化处理。将三维数组转为 1 维数组
   * 为方便实现，三维数组为规则矩阵数组
   *
   * @param obj 三维 int 类型数组
   * @return 一维数组
   */
  public static int[] flat3D(int[][][] obj) {
    int row = obj.length;
    int column = obj[0].length;
    int depth = obj[0][0].length;
    int[] ret = new int[row * column * depth];
    for (int i = 0; i < row; i++) {
      for (int j = 0; j < column; j++) {
        for (int k = 0; k < depth; k++) {
          ret[(i * column + j) * depth + k] = obj[i][j][k];
        }
      }
    }
    return ret;
  }

  public static float[][] flat3DTo2D(float[][][] obj) {
    float[][] res = new float[obj.length * obj[0].length][];
    int index = 0;
    for (int i = 0; i < obj.length; i++) {
      for (int j = 0; j < obj[i].length; j++) {
        res[index++] = obj[i][j];
      }
    }
    return res;
  }

  /**
   * 数组扁平化处理。将二维数组转为 1 维数组
   * 为方便实现，二维数组为规则矩阵数组
   *
   * @param obj 二维 float 类型数组
   * @return 一维数组
   */
  public static float[] flat2D(float[][] obj) {
    int row = obj.length;
    int column = obj[0].length;
    float[] ret = new float[row * column];
    for (int i = 0; i < row; i++) {
      for (int j = 0; j < column; j++) {
        ret[i * column + j] = obj[i][j];
      }
    }
    return ret;
  }

  /**
   * 二维数组数组扁平
   * 并不是从第一行开始
   * 而是从最后一行开始向第一行开始拼接
   *
   * @param obj 二维数组
   * @return
   */
  public static float[] flat2DFormFromLast(float[][] obj) {
    int row = obj.length;
    int column = obj[0].length;
    float[] ret = new float[row * column];
    int index = 0;
    for (int i = row - 1; i >= 0; i--) {
      for (int j = 0; j < column; j++) {
        ret[index] = obj[i][j];
        index++;
      }
    }
    return ret;
  }

  /**
   * 二维数组扁平
   * 并不是一行一行拼接而是一列一列拼接
   *
   * @param obj 二维数组
   * @return
   */
  public static float[] flat2DFormByColumn(float[][] obj) {
    int row = obj.length;
    int column = obj[0].length;
    float[] ret = new float[row * column];
    for (int i = 0; i < column; i++) {
      for (int j = 0; j < row; j++) {
        ret[i * row + j] = obj[j][i];
      }
    }
    return ret;
  }


  /**
   * 数组扁平化处理。将三维数组转为 1 维数组
   * 为方便实现，三维数组为规则矩阵数组
   *
   * @param obj 三维 float 类型数组
   * @return 一维数组
   */
  public static float[] flat3D(float[][][] obj) {
    int row = obj.length;
    int column = obj[0].length;
    int depth = obj[0][0].length;
    float[] ret = new float[row * column * depth];
    for (int i = 0; i < row; i++) {
      for (int j = 0; j < column; j++) {
        System.arraycopy(obj[i][j], 0, ret, (i * column + j) * depth, depth);
      }
    }
    return ret;
  }

  /**
   * 数组扁平化处理。将二维数组转为 1 维数组
   * 为方便实现，二维数组为规则数组
   *
   * @param obj 二维 double 类型数组
   * @return 一维数组
   */
  public static double[] flat2D(double[][] obj) {
    int row = obj.length;
    int column = obj[0].length;
    double[] ret = new double[row * column];
    for (int i = 0; i < row; i++) {
      System.arraycopy(obj[i], 0, ret, i * row, column);
    }
    return ret;
  }

  /**
   * 数组扁平化处理。将三维数组转为 1 维数组
   * 为方便实现，三维数组为规则数组
   *
   * @param obj 三维 double 类型数组
   * @return 一维数组
   */
  public static double[] flat3D(double[][][] obj) {
    int row = obj.length;
    int column = obj[0].length;
    int depth = obj[0][0].length;
    double[] ret = new double[row * column * depth];
    for (int i = 0; i < row; i++) {
      for (int j = 0; j < column; j++) {
        System.arraycopy(obj[i][j], 0, ret, (i * row + j) * column, depth);
      }
    }
    return ret;
  }

  /**
   * 替换目标值
   *
   * @param sourceNum 原数据值
   * @param targetNum 目标值
   * @param obj       替换数组
   */
  public static void replaceNum(float sourceNum, float targetNum, float[] obj) {
    if (Float.isNaN(sourceNum)) {
      for (int i = 0; i < obj.length; i++) {
        if (Float.isNaN(obj[i])) {
          obj[i] = targetNum;
        }
      }
    } else {
      for (int i = 0; i < obj.length; i++) {
        if (obj[i] == sourceNum) {
          obj[i] = targetNum;
        }
      }
    }
  }

  /**
   * 替换目标值
   *
   * @param sourceNum 原数据值
   * @param targetNum 目标值
   * @param obj       替换数组
   */
  public static void replaceNum(float sourceNum, float targetNum, float[][] obj) {
    if (Float.isNaN(sourceNum)) {
      for (int i = 0; i < obj.length; i++) {
        for (int j = 0; j < obj[0].length; j++) {
          if (Float.isNaN(obj[i][j])) {
            obj[i][j] = targetNum;
          }
        }
      }
    } else {
      for (int i = 0; i < obj.length; i++) {
        for (int j = 0; j < obj[0].length; j++) {
          if (obj[i][j] == sourceNum) {
            obj[i][j] = targetNum;
          }
        }
      }
    }

  }

  /**
   * 一维数组稀释方法
   * 对第一个和最后一个保留
   *
   * @param arr 一维数组
   * @param n   稀释倍数
   * @return 稀释后的数组
   */
  public static float[] arr1DDilution(float[] arr, int n) {
    if (n == 0 || n == 1) //不做稀释
    {
      return arr;
    }
    float[] newArr = new float[arr.length / n + 1]; //稀释后的数组长度为 原数组/稀释倍数
    for (int i = 0; i < newArr.length - 1; i++) {
      newArr[i] = arr[i * n];
    }
    newArr[newArr.length - 1] = arr[arr.length - 1];
    return newArr;
  }

  /**
   * 一维数组稀释方法
   * 对第一个和最后一个保留
   *
   * @param arr 一维数组
   * @param n   稀释倍数
   * @return 稀释后的数组
   */
  public static Float[] arr1DDilution(Float[] arr, int n) {
    if (n == 0 || n == 1) //不做稀释
    {
      return arr;
    }

    Float[] newArr = new Float[arr.length / n + 1]; //稀释后的数组长度为 原数组/稀释倍数
    for (int i = 0; i < newArr.length - 1; i++) {
      newArr[i] = arr[i * n];
    }
    newArr[newArr.length - 1] = arr[arr.length - 1];
    return newArr;
  }

  /**
   * 一维数组稀释方法
   * 对第一个和最后一个保留
   *
   * @param arr 一维数组
   * @param n   稀释倍数
   * @return 稀释后的数组
   */
  public static double[] arr1DDilution(double[] arr, int n) {
    if (n == 0 || n == 1) //不做稀释
    {
      return arr;
    }
    double[] newArr = new double[arr.length / n + 1]; //稀释后的数组长度为 原数组/稀释倍数
    for (int i = 0; i < newArr.length - 1; i++) {
      newArr[i] = arr[i * n];
    }
    newArr[newArr.length - 1] = arr[arr.length - 1];
    return newArr;
  }

  /**
   * 二维数组稀释方法
   * 对第一行第一列和最后一行最后一列保留
   *
   * @param arr 二维数组
   * @param n   行稀释倍数
   * @param m   列稀释倍数
   * @return 稀释后的二维数组
   */
  public static float[][] arr2DDilution(float[][] arr, int n, int m) {
    if (n == 0 && m == 0)   //不做稀释
    {
      return arr;
    }

    if (n == 0) {   //行不稀释
      float[][] newArr = new float[arr.length][];
      for (int i = 0; i < newArr.length; i++) {
        float[] temp = new float[arr[i].length / m + 1];
        for (int j = 0; j < temp.length; j++) {
          /**
           * 如果不到最后一列
           * 按稀释的来，否则获取最后一列
           */
          if (j * m < arr[i].length) {
            temp[j] = arr[i][j * m];
          } else {
            temp[j] = arr[i][arr[i].length - 1];
          }
        }
        newArr[i] = temp;
      }
      return newArr;
    }

    if (m == 0) {   //列不稀释
      float[][] newArr = new float[arr.length / n + 1][];
      for (int i = 0; i < newArr.length; i++) {
        float[] temp = new float[arr[i].length];
        for (int j = 0; j < temp.length; j++) {
          /**
           * 如果不到最后一行
           * 按稀释的来，否则获取最后一行
           */
          if (i * n < arr.length) {
            temp[j] = arr[i * n][j];
          } else {
            temp[j] = arr[arr.length - 1][j];
          }
        }
        newArr[i] = temp;
      }
      return newArr;
    }

    float[][] newArr = new float[arr.length / n + 1][]; //行列都需要稀释
    for (int i = 0; i < newArr.length; i++) {
      float[] temp;
      if (i < newArr.length - 1) {
        temp = new float[arr[i * n].length / m + 1];    //temp长度
      } else {
        temp = new float[arr[arr.length - 1].length / m + 1];
      }
      for (int j = 0; j < temp.length; j++) {
        /**
         * 如果没有到最后一行最后一列按稀释的来
         * 否则获取最后一行最后一列
         */
        if (j * m < arr[i].length && i * n < arr.length) {
          temp[j] = arr[i * n][j * m];
        } else if (j * m >= arr[i].length) {
          temp[j] = arr[i * n][arr[i].length - 1];
        } else if (i * n >= arr.length) {
          temp[j] = arr[arr.length - 1][j * m];
        }
      }
      newArr[i] = temp;
    }
    return newArr;

  }

  /**
   * 二维数组稀释方法
   * 对第一行第一列和最后一行最后一列保留
   *
   * @param arr 二维数组
   * @param n   行稀释倍数
   * @param m   列稀释倍数
   * @return 稀释后的二维数组
   */
  public static double[][] arr2DDilution(double[][] arr, int n, int m) {
    if (n == 0 && m == 0)   //不做稀释
    {
      return arr;
    }

    if (n == 0) {   //行不稀释
      double[][] newArr = new double[arr.length][];
      for (int i = 0; i < newArr.length; i++) {
        double[] temp = new double[arr[i].length / m + 1];
        for (int j = 0; j < temp.length; j++) {
          /**
           * 如果不到最后一列
           * 按稀释的来，否则获取最后一列
           */
          if (j * m < arr[i].length) {
            temp[j] = arr[i][j * m];
          } else {
            temp[j] = arr[i][arr[i].length - 1];
          }
        }
        return newArr;
      }
    }
    if (m == 0) {   //列不稀释
      double[][] newArr = new double[arr.length / n + 1][];
      for (int i = 0; i < newArr.length; i++) {
        double[] temp = new double[arr[i].length];
        for (int j = 0; j < temp.length; j++) {
          /**
           * 如果不到最后一行
           * 按稀释的来，否则获取最后一行
           */
          if (i * n < arr.length) {
            temp[j] = arr[i * n][j];
          } else {
            temp[j] = arr[arr.length - 1][j];
          }
        }
        newArr[i] = temp;
      }
      return newArr;
    }

    double[][] newArr = new double[arr.length / n + 1][]; //行列都需要稀释
    for (int i = 0; i < newArr.length; i++) {
      double[] temp;
      if (i < newArr.length - 1) {
        temp = new double[arr[i * n].length / m + 1];    //temp长度
      } else {
        temp = new double[arr[arr.length - 1].length / m + 1];
      }
      for (int j = 0; j < temp.length; j++) {
        /**
         * 如果没有到最后一行最后一列按稀释的来
         * 否则获取最后一行最后一列
         */
        if (j * m < arr[i].length && i * n < arr.length) {
          temp[j] = arr[i * n][j * m];
        } else if (j * m >= arr[i].length) {
          temp[j] = arr[i * n][arr[i].length - 1];
        } else if (i * n >= arr.length) {
          temp[j] = arr[arr.length - 1][j * m];
        }
      }
      newArr[i] = temp;
    }

    return newArr;

  }

  /**
   * list去重(默认：有序)
   *
   * @param list list集合
   * @return
   */
  public static <T> List<T> distinct(List<T> list) {
    return distinct(list, true);
  }

  /**
   * list去重
   *
   * @param list    list集合
   * @param isOrder 是否有序
   * @param <T>
   * @return 去重后的新list集合
   */
  public static <T> List<T> distinct(List<T> list, boolean isOrder) {
    Set<T> set;
    if (isOrder) {
      set = new TreeSet<>(list);
    } else {
      set = new HashSet<>(list);
    }
    list.clear();
    list.addAll(set);
    return list;
  }

  /**
   * 对List进行去重
   * 保证原始顺序
   *
   * @param list 去重数组
   * @param <T>  包装类型
   * @return
   */
  public static <T> List<T> distinctByLinkedHashSet(List<T> list) {
    LinkedHashSet<T> set = new LinkedHashSet<>(list);
    return new ArrayList<>(set);
  }

  /**
   * 数组转置
   *
   * @param arr
   * @return
   */
  public static float[][] transpose(float[][] arr) {
    int m = arr.length;
    int n = arr[0].length;
    float[][] res = new float[n][m];

    for (int i = 0; i < m; i++) {
      for (int j = 0; j < n; j++) {
        res[j][i] = arr[i][j];
      }
    }
    return res;
  }

  /**
   * 判断list中的元素是否是空值 “”
   *
   * @param list list集合
   * @return
   */
  public static Boolean listIsEmpty(List<String> list) {
    boolean flag = true;
    for (String s : list) {
      if (s.length() != 0) {
        flag = false;
        break;
      }
    }
    return flag;
  }

  /**
   * 一维数组拼接
   *
   * @param a 第一个数组
   * @param b 第二个数组
   * @return 拼接后的数组
   */
  public static float[] arrContact(float[] a, float[] b) {
    if (a != null && b != null) {
      float[] result = new float[a.length + b.length];
      int index = 0;
      for (int i = 0; i < result.length; i++) {
        if (i < a.length) {
          result[i] = a[i];
        } else {
          result[i] = b[index];
          index++;
        }
      }
      return result;
    } else if (b != null) {
      return b;
    } else {
      return a;
    }
  }

  /**
   * 二维数组拼接
   * 二维数组左右拼接而不是上下拼接
   *
   * @param left  左数组
   * @param right 右数组
   * @return
   */
  public static float[][] arrContact(float[][] left, float[][] right) {
    if (left != null && right != null) {
      float[][] result = new float[left.length][left[0].length + right[0].length];
      for (int i = 0; i < result.length; i++) {
        int index = 0;
        for (int j = 0; j < result[i].length; j++) {
          if (j < left[i].length) {
            result[i][j] = left[i][j];
          } else {
            result[i][j] = right[i][index];
            index++;
          }
        }
      }
      return result;
    } else if (left != null) {
      return left;
    } else {
      return right;
    }
  }

  /**
   * 二维数组进行拼接
   * 上下拼接
   *
   * @param top    上面数组
   * @param bottom 下面数组
   * @return
   */
  public static float[][] arrContactByVertical(float[][] top, float[][] bottom) {
    if (top != null && bottom != null) {
      float[][] result = new float[top.length + bottom.length][];
      int index = 0;
      for (int i = 0; i < result.length; i++) {
        if (i < top.length) {
          result[i] = top[i];
        } else {
          result[i] = bottom[index++];
        }
      }
      return result;
    } else if (top != null) {
      return top;
    } else {
      return bottom;
    }
  }

  /**
   * 一维数组倒叙
   *
   * @param arr 一维数组
   * @return
   */
  public static float[] arrReverse(float[] arr) {
    float[] result = new float[arr.length];
    int n = arr.length;
    for (int i = 0; i < n; i++) {
      result[i] = arr[n - 1 - i];
    }
    return result;
  }

  /**
   * 二维数组倒叙
   * 从最后一行到第一行
   *
   * @param arr
   * @return
   */
  public static float[][] arrReverse(float[][] arr) {
    float[][] result = new float[arr.length][];
    int n = arr.length;
    for (int i = 0; i < n; i++) {
      result[i] = arr[n - 1 - i];
    }
    return result;
  }

  /**
   * 从uv数据取其平方根
   * 默认保留四位有效小数
   *
   * @param uu uu数组
   * @param vv vv数组
   * @return
   */
  public static float[][] getDataFromUV(float[][] uu, float[][] vv) {
    return getDataFromUV(uu, vv, 4);
  }


  /**
   * 从uv数据取其平方根
   *
   * @param uu    uu数组
   * @param vv    vv数组
   * @param scale 保留小数位数
   * @return
   */
  public static float[][] getDataFromUV(float[][] uu, float[][] vv, Integer scale) {
    float[][] data2D = new float[uu.length][uu[0].length];
    for (int i = 0; i < uu.length; i++) {
      for (int j = 0; j < uu[i].length; j++) {
        if (!Float.isNaN(uu[i][j]) && !Float.isNaN(vv[i][j])) {
          data2D[i][j] = (float) Arith.round(Math.sqrt(Math.pow(uu[i][j], 2) + Math.pow(vv[i][j], 2)), scale);
        } else {
          data2D[i][j] = Float.NaN;
        }
      }
    }
    return data2D;
  }

  /**
   * 判断数组里面是否全是NaN
   *
   * @param data 二维数组
   * @return
   */
  public static boolean allIsNaN(float[] data) {
    for (float datum : data) {
      if (!Float.isNaN(datum)) {
        return false;
      }
    }
    return true;
  }

  /**
   * 数组从后往前获取
   * 数组进行倒转
   *
   * @param data 原始数据
   * @return
   */
  public static float[][] getBack(float[][] data) {
    float[][] result = new float[data.length][];
    int index = 0;
    for (int i = data.length - 1; i >= 0; i--) {
      result[index++] = data[i];
    }
    return result;
  }


  /**
   * 获取arr数组中的NaN的索引值
   * 如果没有返回arr的长度-1
   *
   * @param arr 待测试的数组
   * @return
   */
  public static int getNaNIndex(float[] arr) {
    for (int i = 0; i < arr.length; i++) {
      if (Float.isNaN(arr[i])) {
        return i;
      }
    }
    return arr.length - 1;
  }

  /**
   * 将多个元素放入到集合中
   * 使用了动态参数
   *
   * @param list 集合数组
   * @param t    元素
   * @param <T>  类型
   * @return
   */
  public static <T> boolean arrayAdd(List<T> list, T... t) {
    return list.addAll(Arrays.asList(t));
  }

  /**
   * 将集合转为float数组
   * 集合只要是number类型即可
   *
   * @param list list集合
   * @param <T>  泛型
   * @return
   */
  public static <T> float[] listToArray(List<T> list) {
    float[] resultArr = new float[list.size()];
    for (int i = 0; i < list.size(); i++) {
      if (!String.valueOf(list.get(i)).equals("NaN")) {
        resultArr[i] = Float.parseFloat(String.valueOf(list.get(i)));
      } else {
        resultArr[i] = Float.NaN;
      }
    }
    return resultArr;
  }

  /**
   * 将数组转化为集合
   *
   * @param arr 数组
   * @return
   */
  public static List<Float> arrayToList(float[] arr) {
    List<Float> list = new ArrayList<>();
    for (float v : arr) {
      list.add(v);
    }
    return list;
  }

  /**
   * float数组转为double数组
   *
   * @param arr float数组
   * @return
   */
  public static double[] floatToDouble(float[] arr) {
    double[] result = new double[arr.length];
    for (int i = 0; i < result.length; i++) {
      result[i] = arr[i];
    }
    return result;
  }

  /**
   * double数组转为float数组
   *
   * @param arr double数组
   * @return
   */
  public static float[] doubleToFloat(double[] arr) {
    float[] result = new float[arr.length];
    for (int i = 0; i < result.length; i++) {
      result[i] = (float) arr[i];
    }
    return result;
  }


  /**
   * 二维数组均分成四块
   * 以后可以写入参是横轴分割块数y轴分割块数
   *
   * @param arr 需要分割的二维数组
   * @return
   */
  public static List<float[][]> divideArray(float[][] arr) {
    List<float[][]> list = new ArrayList<>();
    int xMid = arr.length >> 1;
    int yMid = arr[0].length >> 1;
    float[][] temp0 = new float[xMid][yMid];
    float[][] temp1 = new float[xMid][arr[0].length - yMid];
    float[][] temp2 = new float[arr.length - xMid][yMid];
    float[][] temp3 = new float[arr.length - xMid][arr[0].length - yMid];
    for (int i = 0; i < xMid; i++) {
      System.arraycopy(arr[i], 0, temp0[i], 0, yMid);
      System.arraycopy(arr[i], yMid, temp1[i], 0, arr[0].length - yMid);
    }

    for (int i = xMid; i < arr.length; i++) {
      System.arraycopy(arr[i], 0, temp2[i - xMid], 0, yMid);
      System.arraycopy(arr[i], yMid, temp3[i - xMid], 0, arr[0].length - yMid);
    }
    list.add(temp0);
    list.add(temp1);
    list.add(temp2);
    list.add(temp3);
    return list;
  }


  /**
   * 将2D数组拆分为大致相等的指定大小的块
   * 现在还有一个问题就是把二维数组展成了一维数组
   * 导致后序无法再从一维数组转换成二维数组（待改进看返回值能看出来）
   *
   * @param data    将要分割的二维数组
   * @param xDivide 行分割次数应该大于二维数组的行数否则有问题
   * @param yDivide 列分割次数应该大于二维数组的列数否则有问题
   * @return 如果行列数都可以完全均分返回一个指定列数*长度的三维数组，否则会增加1行或者1列用于存放不能整除的数组
   */
  public static float[][][] splitArray(float[][] data, int xDivide, int yDivide) {
    int numRows = data.length;
    int numCols = data[0].length;

    // 确定每个维度块的大小
    int numBlocksX = numCols / xDivide;
    int numBlocksY = numRows / yDivide;
    yDivide = (numRows % yDivide == 0 ? yDivide : yDivide + 1);
    xDivide = numCols % xDivide == 0 ? xDivide : xDivide + 1;
    float[][][] result = new float[yDivide][xDivide][];

    for (int y = 0; y < yDivide; y++) {
      for (int x = 0; x < xDivide; x++) {
        int startX = x * numBlocksX;
        int startY = y * numBlocksY;
        int endX = Math.min(startX + numBlocksX, numCols);
        int endY = Math.min(startY + numBlocksY, numRows);

        int width = endX - startX;
        int height = endY - startY;

        float[] blockData = new float[width * height];
        int index = 0;

        for (int row = startY; row < endY; row++) {
          for (int col = startX; col < endX; col++) {
            blockData[index++] = data[row][col];
          }
        }

        result[y][x] = blockData;
      }
    }

    return result;
  }

  /**
   * 数组分割，左闭右开
   *
   * @param arr  原始数组
   * @param from 开始
   * @param to   结束
   * @return
   */
  public static float[] subArray(float[] arr, int from, int to) {
    if (from < 0 || to > arr.length || from > to) {
      System.out.println("from = " + from);
      System.out.println("to = " + to);
      throw new IllegalArgumentException("非法索引值");
    }
    float[] res = new float[to - from];
    System.arraycopy(arr, from, res, 0, res.length);
    return res;
  }

  /**
   * 由list合并填充成二维数组
   *
   * @param list   原始文件
   * @param row    行数
   * @param column 列数
   * @return
   */
  public static <T> T[][] fill2D(List<T> list, int row, int column, Class<T> clazz) {
    if (list.size() < row * column) {
      throw new ArrayIndexOutOfBoundsException("数组越界检查list长度和拼接行和列的长度");
    }
    T[][] resArr = (T[][]) Array.newInstance(clazz, row, column);
    int index = 0;
    for (int i = 0; i < resArr.length; i++) {
      for (int j = 0; j < resArr[i].length; j++) {
        resArr[i][j] = list.get(index++);
      }
    }
    return resArr;
  }

  /**
   * 三位数组重新排列，用于三维数据第一维是深度变成第一维是纬度或者经度最后一维是深度
   *
   * @param data 三维数据
   * @return
   */
  public static float[][][] data3DSuction(float[][][] data) {
    float[][][] res = new float[data[0].length][data[0][0].length][data.length];

    for (int i = 0; i < data[0].length; i++) {
      for (int j = 0; j < data[0][0].length; j++) {
        int index = 0;
        while (index < data.length) {
          res[i][j][index] = data[index++][i][j];
        }
      }
    }
    return res;
  }
}

